#include <windows.h>
#include <stdio.h>
#include "screen.h"
#include "defines.h"
#include "charInfo.h"

Screen::Screen() {
	m_default.Char = SCREEN_CLEAR_CHAR;
	m_default.Color = COLOR_SCREEN;
}

Screen::~Screen() {
	if( m_buffer != NULL ) {
		delete [] m_buffer;
	}

	if( m_hScreen != INVALID_HANDLE_VALUE ) {
		CloseHandle( m_hScreen );
	}
}

bool Screen::init() {
	m_hScreen = GetStdHandle( STD_OUTPUT_HANDLE );

	SetConsoleTitle( GAME_TITLE );

	if( m_hScreen != INVALID_HANDLE_VALUE ) {
			GetConsoleScreenBufferInfo( m_hScreen, &m_info );
			m_info.dwSize.X = SCREEN_SIZE_X;
			m_info.dwSize.Y = SCREEN_SIZE_Y + SCREEN_EXTRA_LINES;

			m_screenSize = m_info.dwSize;

			SetConsoleScreenBufferSize( m_hScreen, m_screenSize );

			SMALL_RECT windowSize = { 0, 0, SCREEN_SIZE_X - 1, SCREEN_SIZE_Y };

			SetConsoleWindowInfo( m_hScreen, true, &windowSize );
			CONSOLE_CURSOR_INFO curInfo;
			curInfo.dwSize = 10;
			curInfo.bVisible = false;
			SetConsoleCursorInfo( m_hScreen, &curInfo );


			#ifdef DEBUGMODE
				printf( "Screen: %d X %d\nBuffer: %d\n", m_screenSize.X, m_screenSize.Y, getBufferSize() );
			#endif

			m_buffer = new CharInfo[getBufferSize()];
			clearBuffer();

			#ifndef DEBUGMODE
				clearScreen();
			#endif
			return true;
	} else {
		return false;
	}
}

void Screen::invertColor( int a_x, int a_y ) {
	WORD copy;
	int xy = bufXY( a_x, a_y );
	copy = m_buffer[xy].Color;

	m_buffer[xy].Color = ( m_buffer[xy].Color << 4 ) | ( copy >> 4 );
}

void Screen::displayBuffer() {

	if( m_hScreen == INVALID_HANDLE_VALUE )
		return;

#ifdef DEBUGMODE
	printf( "in displayBuffer()\n" );
#endif

	COORD topLeft = { 0, 0 };

#ifndef DEBUGMODE
	SetConsoleCursorPosition( m_hScreen, topLeft );
#endif

	for( int i = 0; i < getBufferSize(); i++ ) {
		SetConsoleTextAttribute( m_hScreen, m_buffer[i].Color );
		putchar( (int) m_buffer[i].Char );
	}
//	putchar( (int) '\n' ); If it's at the end, it should not need to do this -Kaero
}

COORD Screen::displayAt( int a_x, int a_y, char *a_str ) {
	int atX = a_x, atY = a_y;
	COORD ret;

	if( m_hScreen == INVALID_HANDLE_VALUE ) {
		ret.X = 0;
		ret.Y = 0;

		return ret;
	}

	#ifdef DEBUGMODE
		printf( "In displayAt()...\nDisplaying \"%s\" at ( %d, %d )\n", a_str, a_x, a_y );
	#endif

	if( a_x * a_y < getBufferSize() ) {
		for( int i = 0; a_str[i] != '\0'; ++i ) {
			if( atX * atY < getBufferSize() ) {
				if( atX >= m_info.dwSize.X ) {
					++atY;
					atX = a_x;
				}
				m_buffer[bufXY( atX, atY )].Color = m_default.Color;
				m_buffer[bufXY( atX, atY )].Char = a_str[i];
			} else {
				ret.X = ret.Y = 0;
				return ret;
			}
			++atX;
		}

	} else {
		ret.X = ret.Y = 0;
		return ret;
	}

	ret.X = atX;
	ret.Y = atY;

	return ret;
}
void Screen::setAt( int a_x, int a_y, char a_char, WORD a_color ) {
	int xy = bufXY( a_x, a_y );

	if( xy >= 0 && xy < getBufferSize() ) {
		m_buffer[xy].Char = a_char;
		m_buffer[xy].Color = a_color;
	}
}
void Screen::clearScreen() {
	if( m_hScreen != INVALID_HANDLE_VALUE ) {
		DWORD countDone; 
		COORD topleft = {0, 0}; 
		SetConsoleTextAttribute(m_hScreen, m_default.Color); 
		FillConsoleOutputAttribute (m_hScreen, m_default.Color, m_screenSize.X * m_screenSize.Y, topleft, &countDone); 
		FillConsoleOutputCharacter (m_hScreen, m_default.Char, m_screenSize.X * m_screenSize.Y, topleft, &countDone);
	}
}

void Screen::clearBuffer() {
	if( m_buffer != NULL ) {
		for( int i = 0; i < getBufferSize(); i++ ) {
			m_buffer[i].Color = m_default.Color;
			m_buffer[i].Char = m_default.Char;
		}
	}
}